package run.iget.framework.desensitization.serializer;

import java.io.IOException;
import java.util.Objects;
import java.util.function.Function;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;

import lombok.extern.slf4j.Slf4j;
import run.iget.framework.desensitization.annotation.Desensitization;
import run.iget.framework.desensitization.context.DesensitizationThreadLocalContext;

/**
 * 代码千万行，注释第一行，注释不规范，迭代两行泪
 * ---------------类描述-----------------
 * jackson序列化输出字段脱敏
 * ---------------类描述-----------------
 * @author 大周
 * @since 2022/8/22 11:58
 */
@Slf4j
public class DesensitizeSerializer extends JsonSerializer<String> implements ContextualSerializer {

    private Function<String, String> desensitizationHandler;

    public DesensitizeSerializer() {
    }

    public DesensitizeSerializer(Function desensitizationHandler) {
        this.desensitizationHandler = desensitizationHandler;
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty)
            throws JsonMappingException {
        log.info("---------------------------------createContextual");
        if (Objects.isNull(beanProperty)) {
            return serializerProvider.findNullValueSerializer(beanProperty);
        }
        // 非 String 类直接跳过
        if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
            Function function = getDesensitization(beanProperty);
            if (function != null) {
                return new DesensitizeSerializer(function);
            }
        }
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }

    @Override
    public void serialize(String source, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
            throws IOException {
        if (DesensitizationThreadLocalContext.isNeedDesensitization() && Objects.nonNull(desensitizationHandler)) {
            jsonGenerator.writeString(desensitizationHandler.apply(source));
        } else {
            jsonGenerator.writeString(source);
        }
    }

    private Function getDesensitization(BeanProperty beanProperty) {
        Desensitization desensitization = beanProperty.getAnnotation(Desensitization.class);
        if (desensitization == null) {
            desensitization = beanProperty.getContextAnnotation(Desensitization.class);
        }
        if (desensitization == null) {
            return null;
        }
        Function function = desensitization.type().getFunction();
        Class<? extends Function> handlerClass = desensitization.handler();
        if (handlerClass != null) {
            try {
                function = handlerClass.newInstance();
            } catch (Exception e) {
                log.error("can not newInstance", e);
            }
        }
        return function;
    }
}
